home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgLangD.iso / BORLAND TURBO / TUTORIAL.PAK / CPPOCF3.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1997-05-06  |  29.7 KB  |  1,297 lines

  1. // ---------------------------------------------------------------------------
  2. // Copyright (C) 1994 Borland International
  3. // Simple OLE Container using OCF
  4. // ---------------------------------------------------------------------------
  5. #include <ocf/pch.h>
  6. #include <ocf/ocapp.h>
  7. #include <ocf/ocdoc.h>
  8. #include <ocf/ocview.h>
  9. #include <ocf/ocremvie.h>
  10. #include <ocf/ocpart.h>
  11. #include <ocf/ocstorag.h>
  12. #include <classlib/arrays.h>
  13. #include <cstring.h>
  14. #include <windowsx.h>
  15. #include "cppocf3.h"
  16. #include "ocfhlpr.h"
  17.  
  18. //
  19. // MDI Window Style constants
  20. //
  21. const DWORD MDIClientStyle = MDIS_ALLCHILDSTYLES | WS_GROUP | WS_TABSTOP |
  22.                              WS_CLIPCHILDREN|WS_CLIPSIBLINGS | WS_VSCROLL|
  23.                              WS_HSCROLL | WS_VISIBLE| WS_CHILD;
  24. const DWORD MDIChildStyle  = WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS |
  25.                              WS_CLIPCHILDREN |WS_SYSMENU | WS_CAPTION |
  26.                              WS_THICKFRAME |WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
  27.  
  28. //
  29. // Macros/constants
  30. //
  31. #define DEFEXT  "sc3"
  32. #define DEFDESC "Sample Container 3"
  33.  
  34.  
  35. //
  36. // Global variables
  37. //
  38. const  char childClassName[]  = "__fenΩtreOLE";
  39. const  char frameClassName[]  = "__fenΩtrePrincipale";
  40. const  char appTitle[]        = DEFDESC;
  41. const  char untitled[]        = "Untitled";
  42. const  char AboutMsg[]        = "C++ OLE Container using OCF";
  43. const  char AboutTitle[]      = "About "DEFDESC;
  44.  
  45. static char FileName[MAXPATH] = {0};
  46. const  char Filter[]          = DEFDESC"\0*."DEFEXT"\0";
  47.  
  48.  
  49. //
  50. // App/Frame related variables
  51. //
  52. HWND      Frame     = 0;
  53. HWND      Client    = 0;
  54. HWND      StatusBar = 0;
  55. HMENU     FrameMenu = 0;
  56. uint      ChildID   = 0x1000;
  57. HINSTANCE HInstance = 0;
  58.  
  59.  
  60. //
  61. // OCF variables
  62. //
  63. static TRegLink* RegLinkHead = 0;
  64. static TRect     Decorations(0, 0, 0, 0);
  65.  
  66. //
  67. // registration information
  68. //
  69. REGISTRATION_FORMAT_BUFFER(100)
  70.  
  71. BEGIN_REGISTRATION(AppReg)
  72.   REGDATA(clsid,    "{8646DB82-94E5-101B-B01F-00608CC04F66}")
  73.   REGDATA(appname,  "SampContainer")
  74. END_REGISTRATION
  75.  
  76. //
  77. // Register clipboard formats
  78. //
  79. BEGIN_REGISTRATION(DocReg)
  80.   REGDATA(progid,      "Sample.Container.3")
  81.   REGDATA(description, DEFDESC)
  82.   REGDATA(extension,   DEFEXT)
  83.   REGDATA(docfilter,   "*." DEFEXT)
  84.   REGFORMAT(0, ocrEmbedSource,  ocrContent,  ocrIStorage, ocrGet)
  85.   REGFORMAT(1, ocrMetafilePict, ocrContent,  ocrMfPict|ocrStaticMed, ocrGet)
  86.   REGFORMAT(2, ocrBitmap, ocrContent,  ocrGDI|ocrStaticMed, ocrGet)
  87.   REGFORMAT(3, ocrDib, ocrContent,  ocrHGlobal|ocrStaticMed, ocrGet)
  88.   REGFORMAT(4, ocrLinkSource, ocrContent,  ocrIStream, ocrGet)
  89. END_REGISTRATION
  90. static TRegLink  DocLink(DocReg, RegLinkHead);
  91.  
  92.  
  93. //
  94. // Application's Entry Point
  95. //
  96. int PASCAL
  97. WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  98.       char far* lpCmdLine, int nCmdShow)
  99. {
  100.   HInstance = hInstance;
  101.   try {
  102.     // Initialize OLE
  103.     //
  104.     string cmdLine(lpCmdLine);
  105.     TOleInitEx oleInit(::AppReg, /*Factory Callback*/0, cmdLine,
  106.                        ::RegLinkHead, hInstance);
  107.  
  108.     // Initialize application related items (eg. Window Classes)
  109.     //
  110.     if (!hPrevInstance  && (!InitFrame(hInstance) || !InitChild(hInstance)))
  111.       return 0;
  112.  
  113.     // Initialize per-instanace related items (eg. create main window)
  114.     //
  115.     if (!InitInstance(hInstance, nCmdShow))
  116.       return 0;
  117.  
  118.     // Standard Windows message loop
  119.     //
  120.     MSG msg;
  121.     while (GetMessage(&msg, 0, 0, 0)) {
  122.       if (!TranslateMDISysAccel(Client, &msg)) {
  123.         TranslateMessage(&msg);
  124.         DispatchMessage(&msg);
  125.       }
  126.     }
  127.   }
  128.  
  129.   catch (TXBase& xbase) {
  130.     MessageBox(GetFocus(), xbase.why().c_str(), "Exception caught", MB_OK);
  131.   }
  132.   return 0;
  133. }
  134.  
  135.  
  136. //
  137. // Initialize main frame
  138. //
  139. bool
  140. InitFrame(HINSTANCE hInstance)
  141. {
  142.   WNDCLASS wc;
  143.   wc.style          = CS_HREDRAW | CS_VREDRAW;
  144.   wc.lpfnWndProc    = (WNDPROC)MainWndProc;
  145.   wc.cbClsExtra     = 0;
  146.   wc.cbWndExtra     = sizeof(TOleFrameWin*);
  147.   wc.hInstance      = hInstance;
  148.   wc.hIcon          = LoadIcon(0, IDI_APPLICATION);
  149.   wc.hCursor        = LoadCursor(0, IDC_ARROW);
  150.   wc.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  151.   wc.lpszMenuName   = 0;
  152.   wc.lpszClassName  = frameClassName;
  153.  
  154.   return (RegisterClass(&wc) != 0);
  155. }
  156.  
  157.  
  158. //
  159. // Initialize instance and display the main window
  160. //
  161. bool
  162. InitInstance(HINSTANCE hInstance, int nCmdShow)
  163. {
  164.   Frame = CreateWindow(frameClassName, appTitle,
  165.                        WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN |
  166.                        WS_CLIPSIBLINGS,
  167.                        CW_USEDEFAULT, CW_USEDEFAULT,
  168.                        CW_USEDEFAULT, CW_USEDEFAULT,
  169.                        0,
  170.                        0,
  171.                        hInstance,
  172.                        0);
  173.   if (!Frame)
  174.     return false;
  175.  
  176.   ShowWindow(Frame, nCmdShow);
  177.   UpdateWindow(Frame);
  178.  
  179.   return true;
  180. }
  181.  
  182.  
  183. //
  184. // Accessor to retrieve OLE helper object associated with an HWND
  185. //
  186. TOleFrameWin*
  187. GetOleFrameWinObj(HWND hwnd)
  188. {
  189.   return (TOleFrameWin*)(LONG)GetWindowLong(hwnd, 0);
  190. }
  191.  
  192.  
  193. //
  194. // Function to associate an OLE Helper object with a window
  195. //
  196. void
  197. SetOleFrameWinObj(HWND hwnd, TOleFrameWin* oleFrameWinObj)
  198. {
  199.   SetWindowLong(hwnd, 0, (LONG)oleFrameWinObj);
  200. }
  201.  
  202.  
  203. LRESULT
  204. MainWnd_DefProc(HWND hwnd, uint msg, WPARAM wParam, LPARAM lParam)
  205. {
  206.   return DefFrameProc(hwnd, Client, msg, wParam, lParam);
  207. }
  208.  
  209.  
  210. //
  211. // Returns frame's active child window handle
  212. //
  213. HWND
  214. MainWnd_GetActiveChild(HWND /*hwnd*/)
  215. {
  216.   return IsWindow(Client) ? FORWARD_WM_MDIGETACTIVE(Client, SendMessage) : 0;
  217. }
  218.  
  219.  
  220. //
  221. // Returns frame window
  222. //
  223. HWND
  224. GetFrame()
  225. {
  226.    return Frame;
  227. }
  228.  
  229.  
  230. //
  231. // Sets the Frame's menu
  232. //
  233. void
  234. MainWnd_SetMenu(HWND hwnd, HMENU hMenu, int winIndex = 0)
  235. {
  236.   if (!hMenu && FrameMenu)
  237.     hMenu = FrameMenu;
  238.  
  239.   if (IsWindow(Client)) {
  240.     FORWARD_WM_MDISETMENU(Client, TRUE /*FALSE*/, hMenu, GetSubMenu(hMenu, winIndex),
  241.                           SendMessage);
  242.     DrawMenuBar(hwnd);
  243.   }
  244. }
  245.  
  246.  
  247. //
  248. // Closes all MDI Child Windows
  249. //
  250. void
  251. MainWnd_CloseAll(HWND hwnd)
  252. {
  253.   if (!IsWindow(Client))
  254.     return;
  255.  
  256.   //
  257.   // Iterate through children to close them...
  258.   //
  259.   HWND child = MainWnd_GetActiveChild(hwnd);
  260.   while (IsWindow(child)) {
  261.     HWND next = GetWindow(child, GW_HWNDNEXT);
  262.     FORWARD_WM_MDIDESTROY(Client, child, SendMessage);
  263.     child = next;
  264.   }
  265. }
  266.  
  267.  
  268. bool
  269. MainWnd_OnCreate(HWND hwnd, CREATESTRUCT FAR* /*lpCreateStruct*/)
  270. {
  271.   TOleFrameWin* oleFrameWinObj = new TOleFrameWin(hwnd);
  272.   SetOleFrameWinObj(hwnd, oleFrameWinObj);
  273.  
  274.   // Allow OLE Helper to perform initialization
  275.   //
  276.   oleFrameWinObj->OnCreate();
  277.  
  278.   // Set Frame window's menu
  279.   //
  280.   HINSTANCE hInstance = GetWindowInstance(hwnd);
  281.   FrameMenu           = LoadMenu(hInstance, MAKEINTRESOURCE(ID_MAINMENU));
  282.  
  283.   if (FrameMenu)
  284.     SetMenu(hwnd, FrameMenu);
  285.  
  286.   // Create MDI Client window
  287.   //
  288.   CLIENTCREATESTRUCT cs;
  289.   memset(&cs, 0,  sizeof(cs));
  290.   cs.hWindowMenu  = FrameMenu ? GetSubMenu(FrameMenu, 0) : 0;
  291.   cs.idFirstChild = ChildID;
  292.   Client = CreateWindow("MDICLIENT", "",
  293.                         MDIClientStyle,
  294.                         0, 0, 0, 0,
  295.                         hwnd,
  296.                         0,
  297.                         hInstance,
  298.                         (LPSTR)(LPCLIENTCREATESTRUCT)&cs);
  299.   return (Client != 0);
  300. }
  301.  
  302.  
  303. //
  304. //
  305. //
  306. void
  307. MainWnd_OnDestroy(HWND hwnd)
  308. {
  309.   //
  310.   // Allow OLE Helper object to perform cleanup
  311.   //
  312.   TOleFrameWin* oleFrameWinObj = GetOleFrameWinObj(hwnd);
  313.   oleFrameWinObj->OnDestroy();
  314.  
  315.   // Delete OLE Helper object
  316.   //
  317.   delete oleFrameWinObj;
  318.  
  319.   // Usual posting of WM_QUIT
  320.   //
  321.   PostQuitMessage(0);
  322. }
  323.  
  324.  
  325. //
  326. // Handles WM_CLOSE
  327. //
  328. void
  329. MainWnd_OnClose(HWND hwnd)
  330. {
  331.   //
  332.   // First restore the frame's original menu to allow proper cleanup
  333.   //
  334.   if (FrameMenu && GetMenu(hwnd) != FrameMenu) {
  335.     MainWnd_SetMenu(hwnd, FrameMenu);
  336.   }
  337.  
  338.   //
  339.   // Close all children
  340.   //
  341.   MainWnd_CloseAll(hwnd);
  342.  
  343.   //
  344.   // Pass on to default proc
  345.   //
  346.   FORWARD_WM_CLOSE(hwnd, MainWnd_DefProc);
  347. }
  348.  
  349.  
  350. //
  351. // Create MDI child
  352. //
  353. HWND
  354. MainWnd_CreateMDIChild(const char* className,
  355.                        const char* title,
  356.                        DWORD style,
  357.                        int x, int y, int w, int h, HWND parent,
  358.                        HINSTANCE hInstance, LPARAM lParam)
  359. {
  360.   MDICREATESTRUCT mcs;
  361.   mcs.szClass = className;
  362.   mcs.szTitle = title;
  363.   mcs.hOwner  = hInstance;
  364.   mcs.x       = x;
  365.   mcs.y       = y;
  366.   mcs.cx      = w;
  367.   mcs.cy      = h;
  368.   mcs.style   = style;
  369.   mcs.lParam  = lParam;
  370.  
  371.   return FORWARD_WM_MDICREATE(parent, &mcs, SendMessage);
  372. }
  373.  
  374.  
  375. //
  376. // Handle request to create a new MDI Child
  377. //
  378. HWND
  379. MainWnd_NewChild(HWND hwnd)
  380. {
  381.   return IsWindow(Client) ?
  382.          MainWnd_CreateMDIChild(childClassName, untitled, MDIChildStyle,
  383.                                 CW_USEDEFAULT, CW_USEDEFAULT,
  384.                                 CW_USEDEFAULT, CW_USEDEFAULT,
  385.                                 Client, GetWindowInstance(hwnd), 0) : 0;
  386. }
  387.  
  388.  
  389. //
  390. // Handles WM_COMMAND sent to frame window
  391. //
  392. void
  393. MainWnd_OnCommand(HWND hwnd, int id, HWND hwndCtl, uint codeNotify)
  394. {
  395.   switch (id) {
  396.     // Handle Exit Request
  397.     //
  398.     case CM_FILEEXIT:
  399.       PostMessage(hwnd, WM_CLOSE, 0, 0);
  400.       break;
  401.  
  402.     case CM_FILENEW:
  403.       MainWnd_NewChild(hwnd);
  404.       break;
  405.  
  406.     case CM_FILEOPEN:
  407.       // Prompt user - Create new window - have child load data
  408.       //
  409.       if (GetOpenFileName(hwnd, Filter, FileName, sizeof(FileName)))
  410.         FORWARD_WM_COMMAND(MainWnd_NewChild(hwnd), id, hwndCtl,
  411.                            codeNotify, SendMessage);
  412.       break;
  413.  
  414.     case CM_FILESAVE:
  415.     case CM_FILESAVEAS: {
  416.       // Tell active child to save parts
  417.       //
  418.       HWND child = MainWnd_GetActiveChild(hwnd);
  419.       FORWARD_WM_COMMAND(child, id, hwndCtl, codeNotify, SendMessage);
  420.       break;
  421.     }
  422.  
  423.     case CM_WINDOWCASCADECHILDREN:
  424.       FORWARD_WM_MDICASCADE(Client, 0, SendMessage);
  425.       break;
  426.  
  427.     case CM_WINDOWTILECHILDREN:
  428.       FORWARD_WM_MDITILE(Client, 0, SendMessage);
  429.       break;
  430.  
  431.     case CM_WINDOWARRANGEICONS:
  432.       FORWARD_WM_MDIICONARRANGE(Client, SendMessage);
  433.       break;
  434.  
  435.     case CM_WINDOWCLOSEALL:
  436.       MainWnd_CloseAll(hwnd);
  437.       break;
  438.  
  439.     case CM_HELPABOUT:
  440.       MessageBox(hwnd, AboutMsg, AboutTitle, MB_OK|MB_ICONINFORMATION);
  441.       break;
  442.  
  443.     // If we do not process the command, pass it on
  444.     //
  445.     default: {
  446.       // forward messages to MDI frame
  447.       FORWARD_WM_COMMAND(hwnd, id, hwndCtl, codeNotify, MainWnd_DefProc);
  448.  
  449.       // forward to active child too
  450.       HWND child = MainWnd_GetActiveChild(hwnd);
  451.       if (child)
  452.         FORWARD_WM_COMMAND(child, id, hwndCtl, codeNotify, SendMessage);
  453.     }
  454.   }
  455. }
  456.  
  457.  
  458. //
  459. // Resizes Client window
  460. //
  461. void
  462. MainWnd_ResizeClient(HWND hwnd)
  463. {
  464.   if (IsWindow(Client)) {
  465.     TRect rect;
  466.     GetClientRect(hwnd, &rect);
  467.     MoveWindow(Client,
  468.                rect.left    + Decorations.left,
  469.                rect.top     + Decorations.top,
  470.                rect.right   - Decorations.right,
  471.                rect.bottom  - Decorations.bottom,
  472.                true);
  473.   }
  474. }
  475.  
  476.  
  477. //
  478. // Handles WM_SIZE be resizing client window
  479. //
  480. void
  481. MainWnd_OnSize(HWND hwnd, uint /*state*/, int /*cx*/, int /*cy*/)
  482. {
  483.   MainWnd_ResizeClient(hwnd);
  484. }
  485.  
  486.  
  487. //
  488. // Handles WM_INITMENU message
  489. //
  490. void
  491. MainWnd_OnInitMenu(HWND hwnd, HMENU hMenu)
  492. {
  493.   //
  494.   // Pass on to child to handle menu enabling/disabling
  495.   //
  496.   HWND child = MainWnd_GetActiveChild(hwnd);
  497.   if (child)
  498.     FORWARD_WM_INITMENU(child, hMenu, SendMessage);
  499. }
  500.  
  501.  
  502. //
  503. // Handles OCAPPFRAMERECT
  504. //
  505. bool
  506. MainWnd_OnOcAppFrameRect(HWND hwnd, TRect far* rect)
  507. {
  508.   GetClientRect(hwnd, rect);
  509.   return true;
  510. }
  511.  
  512.  
  513. //
  514. // Pass on OCAPPINSMENU to active child so it may merge in its menu
  515. //
  516. bool
  517. MainWnd_OnOcAppInsMenus(HWND hwnd, TOcMenuDescr far* sharedMenu)
  518. {
  519.   HWND child = MainWnd_GetActiveChild(hwnd);
  520.   return child ? GetOleWinObj(child)->OnOcAppInsMenus(sharedMenu) : false;
  521. }
  522.  
  523.  
  524. //
  525. // Set menu handle specified by active child
  526. //
  527. bool
  528. MainWnd_OnOcAppMenus(HWND hwnd, TOcMenuDescr far* menuDescr)
  529. {
  530.   HWND child = MainWnd_GetActiveChild(hwnd);
  531.   if (child) {
  532.     HMENU menu = GetOleWinObj(child)->OnOcAppMenus(menuDescr);
  533.     if (menu) {
  534.       MainWnd_SetMenu(hwnd, menu);
  535.       return true;
  536.     }
  537.   }
  538.   return false;
  539. }
  540.  
  541.  
  542. bool
  543. MainWnd_OnOcAppProcessMsg(HWND, MSG far*)
  544. {
  545.   return false;
  546. }
  547.  
  548.  
  549. bool
  550. MainWnd_OnOcAppBorderSpaceReq(HWND, TRect far*)
  551. {
  552.   return true;  // We'll negotiate anything!
  553. }
  554.  
  555.  
  556. bool
  557. MainWnd_OnOcAppBorderSpaceSet(HWND hwnd, TRect far* rect)
  558. {
  559.   if (rect) {
  560.     // Store space requested
  561.     //
  562.     Decorations = *rect;
  563.  
  564.     // Resize our client window
  565.     //
  566.     MainWnd_ResizeClient(hwnd);
  567.   }
  568.   return true;
  569. }
  570.  
  571.  
  572. //
  573. //
  574. //
  575. void
  576. MainWnd_OnOcAppStatusText(HWND, const char far* /*text*/)
  577. {
  578. }
  579.  
  580.  
  581. //
  582. //
  583. //
  584. void
  585. MainWnd_OnOcAppRestoreUI(HWND hwnd)
  586. {
  587.   HWND child = MainWnd_GetActiveChild(hwnd);
  588.   if (child) {
  589.     HMENU menu = GetOleWinObj(child)->OnOcAppRestoreUI();
  590.     MainWnd_SetMenu(hwnd, menu ? menu : FrameMenu);
  591.   }
  592.  
  593.   // Reset space allocated for decorations
  594.   //
  595.   Decorations.SetNull();
  596.   MainWnd_ResizeClient(hwnd);
  597. }
  598.  
  599.  
  600. //
  601. // Subdispatch OC_... messages
  602. //
  603. LRESULT
  604. MainWnd_OnOcEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
  605. {
  606.   switch (wParam) {
  607.     HANDLE_OCF(hwnd, OC_APPFRAMERECT,       MainWnd_OnOcAppFrameRect);
  608.     HANDLE_OCF(hwnd, OC_APPBORDERSPACESET,  MainWnd_OnOcAppBorderSpaceSet);
  609.     HANDLE_OCF(hwnd, OC_APPBORDERSPACEREQ,  MainWnd_OnOcAppBorderSpaceReq);
  610.     HANDLE_OCF(hwnd, OC_APPINSMENUS,        MainWnd_OnOcAppInsMenus);
  611.     HANDLE_OCF(hwnd, OC_APPMENUS,           MainWnd_OnOcAppMenus);
  612.     HANDLE_OCF(hwnd, OC_APPRESTOREUI,       MainWnd_OnOcAppRestoreUI);
  613.  
  614.     default:
  615.       return 0;
  616.   }
  617. }
  618.  
  619.  
  620. //
  621. // Standard message-handler routine for main window
  622. //
  623. LRESULT CALLBACK _export
  624. MainWndProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  625. {
  626.   switch (message) {
  627.     HANDLE_MSG(hwnd, WM_CREATE,         MainWnd_OnCreate);
  628.     HANDLE_MSG(hwnd, WM_CLOSE,          MainWnd_OnClose);
  629.     HANDLE_MSG(hwnd, WM_DESTROY,        MainWnd_OnDestroy);
  630.     HANDLE_MSG(hwnd, WM_COMMAND,        MainWnd_OnCommand);
  631.     HANDLE_MSG(hwnd, WM_SIZE,           MainWnd_OnSize);
  632.     HANDLE_MSG(hwnd, WM_INITMENU,       MainWnd_OnInitMenu);
  633.  
  634.     // handle the OCF events sent to the frame window
  635.     //
  636.     HANDLE_MSG(hwnd, WM_OCEVENT,  MainWnd_OnOcEvent);
  637.   }
  638.   return MainWnd_DefProc(hwnd, message, wParam, lParam);
  639. }
  640.  
  641.  
  642. // ----------------------------------------------------------------------------
  643. //  MDI Child - related functions/handlers
  644. // ----------------------------------------------------------------------------
  645.  
  646.  
  647. //
  648. // View related global variables
  649. //
  650. static HDC DC                 = 0;
  651. static HPEN OldPen            = 0;
  652. static HPEN CurPen            = 0;
  653. static TLine* ScratchLine     = 0;
  654. static int CurrentPenSize     = 1;
  655. static bool MouseCaptured     = false;
  656. static COLORREF CurrentColor  = RGB(0, 0, 0);
  657.  
  658.  
  659. //
  660. // Initialize child window
  661. //
  662. bool
  663. InitChild(HINSTANCE hInstance)
  664. {
  665.   WNDCLASS wcView;
  666.   wcView.style          = CS_DBLCLKS|CS_HREDRAW|CS_VREDRAW;
  667.   wcView.lpfnWndProc    = (WNDPROC) ViewWndProc;
  668.   wcView.cbClsExtra     = 0;
  669.   wcView.cbWndExtra     = sizeof(TOleWin*);
  670.   wcView.hInstance      = hInstance;
  671.   wcView.hIcon          = LoadIcon(0, IDI_APPLICATION);
  672.   wcView.hCursor        = LoadCursor(0, IDC_ARROW);
  673.   wcView.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
  674.   wcView.lpszMenuName   = 0;
  675.   wcView.lpszClassName  = childClassName;
  676.  
  677.   return RegisterClass(&wcView) != 0;
  678. }
  679.  
  680.  
  681. //
  682. // Accessor to retrieve OLE helper object associated with an HWND
  683. //
  684. TOleWin*
  685. GetOleWinObj(HWND hwnd)
  686. {
  687.   return (TOleWin*)(LONG)GetWindowLong(hwnd, 0);
  688. }
  689.  
  690.  
  691. //
  692. // Function to associate an OLE Helper object with a window
  693. //
  694. void
  695. SetOleWinObj(HWND hwnd, TOleWin* oleWinObj)
  696. {
  697.   SetWindowLong(hwnd, 0, (LONG)oleWinObj);
  698. }
  699.  
  700.  
  701. ViewWndData*
  702. GetViewWndData(HWND hwnd)
  703. {
  704.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  705.   return (ViewWndData*)(oleWinObj ? oleWinObj->GetUserInfo() : 0);
  706. }
  707.  
  708.  
  709. ViewWndData*
  710. SetViewWndData(HWND hwnd, ViewWndData* data)
  711. {
  712.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  713.   return (ViewWndData*)(oleWinObj ? oleWinObj->SetUserInfo(data) : 0);
  714. }
  715.  
  716.  
  717. LRESULT
  718. ViewWnd_DefProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  719. {
  720.   return DefMDIChildProc(hwnd, message, wParam, lParam);
  721. }
  722.  
  723.  
  724. //
  725. // view window
  726. //
  727. BOOL
  728. ViewWnd_OnCreate(HWND hwnd, CREATESTRUCT FAR* /*lpCreateStruct*/)
  729. {
  730.   // Create an OLE helper object
  731.   //
  732.   TOleWin* oleWinObj = new TOleWin(hwnd);
  733.   SetOleWinObj(hwnd, oleWinObj);
  734.  
  735.   // Create per window data
  736.   //
  737.   ViewWndData* data = new ViewWndData;
  738.   SetViewWndData(hwnd, data);
  739.  
  740.   // Call the OnCreate method to allow initialization
  741.   //
  742.   oleWinObj->OnCreate();
  743.  
  744.   //
  745.   // Pass the OCF object our menu description
  746.   //
  747.   MenuDescr menuDescr(LoadMenu(GetWindowInstance(hwnd),
  748.                                MAKEINTRESOURCE(ID_CHILDMENU)),
  749.                       1,    // File group      (File)
  750.                       2,    // Edit group      (Edit + Tools)
  751.                       0,    // Container group
  752.                       0,    // Object group
  753.                       1,    // Window group    (Window)
  754.                       1);   // Help group      (Help)
  755.   oleWinObj->SetWinMenu(menuDescr);
  756.  
  757.   return true;
  758. }
  759.  
  760.  
  761. //
  762. // Handles WM_DESTROY message
  763. //
  764. void
  765. ViewWnd_OnDestroy(HWND hwnd)
  766. {
  767.   // cleanup per window data
  768.   //
  769.   ViewWndData* data = SetViewWndData(hwnd, 0);
  770.   delete data;
  771.  
  772.   TOleWin* oleWinObj = GetOleWinObj(hwnd);
  773.  
  774.   //
  775.   // Retrieve and cleanup our menu
  776.   //
  777.   HMENU hMenu = oleWinObj->GetWinMenu();
  778.   if (hMenu)
  779.     DestroyMenu(hMenu);
  780.  
  781.   // Allow OLE Helper to perform cleanup
  782.   //
  783.   oleWinObj->OnDestroy();
  784.  
  785.   // Cleanup C++ object
  786.   //
  787.   delete oleWinObj;
  788.   FORWARD_WM_DESTROY(hwnd, ViewWnd_DefProc);
  789. }
  790.  
  791.  
  792. //
  793. //
  794. //
  795. void
  796. ViewWnd_OnMDIActivate(HWND hwnd, BOOL fActive, HWND /*hwndActivate*/,
  797.                       HWND /*hwndDeactivate*/)
  798. {
  799.   //
  800.   // Reset menu when we're deactivated
  801.   //
  802.   if (!fActive) {
  803.     MainWnd_SetMenu(GetFrame(), 0);
  804.   } else {
  805.     //
  806.     // Set the child's menu when it's activated
  807.     //
  808.     TOleWin* oleWinObj = GetOleWinObj(hwnd);
  809.     HMENU currentMenu  = oleWinObj->GetMergedMenu();
  810.     if (!currentMenu)
  811.       currentMenu = oleWinObj->GetWinMenu();
  812.  
  813.     MainWnd_SetMenu(GetFrame(), currentMenu);
  814.   }
  815. }
  816.  
  817.  
  818. //
  819. //
  820. //
  821. void
  822. ViewWnd_OnSetFocus(HWND hwnd, HWND hwndOldFocus)
  823. {
  824.   GetOleWinObj(hwnd)->OnSetFocus(hwndOldFocus);
  825. }
  826.  
  827.  
  828. //
  829. // Handles WM_PAINT message
  830. //
  831. void
  832. ViewWnd_OnPaint(HWND hwnd)
  833. {
  834.   PAINTSTRUCT ps;
  835.   HDC dc = BeginPaint(hwnd, &ps);
  836.  
  837.   HPEN oldPen;
  838.   ViewWndData* data = GetViewWndData(hwnd);
  839.   if (data) {
  840.     // go through array of lines
  841.     //
  842.     TLinesIterator linesIter(*data->Lines);
  843.     while (linesIter) {
  844.       // about to draw a line
  845.       //
  846.       TLine line = linesIter.Current();
  847.       HPEN pen = CreatePen(PS_INSIDEFRAME, line.PenSize, line.Color);
  848.       oldPen = SelectPen(dc, pen);
  849.  
  850.       // go through the points in a line
  851.       //
  852.       TPointsIterator pointsIter(line);
  853.       bool firstPoint = true;
  854.  
  855.       while (pointsIter) {
  856.         TPoint point = pointsIter.Current();
  857.         if (firstPoint) {
  858.           MoveToEx(dc, point.x, point.y, 0);
  859.           firstPoint = false;
  860.         } else {
  861.           LineTo(dc, point.x, point.y);
  862.         }
  863.         pointsIter++;
  864.       }
  865.  
  866.       SelectPen(dc, oldPen);
  867.       DeletePen(pen);
  868.  
  869.       linesIter++;
  870.     }
  871.   }
  872.  
  873.   // OLE Helper will draw embedded parts
  874.   //
  875.   GetOleWinObj(hwnd)->OnPaint(dc, ps);
  876.  
  877.   EndPaint(hwnd, &ps);
  878. }
  879.  
  880.  
  881. //
  882. // Handles WM_SIZE message
  883. //
  884. void
  885. ViewWnd_OnSize(HWND hwnd, uint /*state*/, int /*cx*/, int /*cy*/)
  886. {
  887.   // Inform OLE Helper object that we've been resized
  888.   //
  889.   GetOleWinObj(hwnd)->OnSize();
  890. }
  891.  
  892.  
  893. //
  894. // Handles CM_FILESAVEAS command
  895. //
  896. void
  897. ViewWnd_OnFileSaveAs(HWND hwnd)
  898. {
  899.   ViewWndData* data = GetViewWndData(hwnd);
  900.   if (data) {
  901.     // Prompt user for file name
  902.     //
  903.     if (GetSaveFileName(hwnd, Filter, FileName, sizeof(FileName))) {
  904.       // Create the file
  905.       //
  906.       TOcDocument* doc = GetOleWinObj(hwnd)->GetOcDoc();
  907.       if (doc) {
  908.         try {
  909.           doc->SaveToFile(FileName);
  910.  
  911.           // Save the embedded objects
  912.           //
  913.           doc->SaveParts(0, true);
  914.  
  915.           // write out user data
  916.           //
  917.           TOcStorage* storage = doc->GetStorage();
  918.           if (storage) {
  919.             // create a storage within the file and save our data into it
  920.             //
  921.             TOcStream stream(*storage, DEFDESC, true, STGM_WRITE);
  922.  
  923.             int numLines = data->Lines->GetItemsInContainer();
  924.             stream.Write(&numLines, sizeof numLines);
  925.  
  926.             // go through array of lines
  927.             //
  928.             TLinesIterator linesIter(*data->Lines);
  929.             while (linesIter) {
  930.               // get a line
  931.               //
  932.               TLine line = linesIter.Current();
  933.               int numPoints = line.GetItemsInContainer();
  934.  
  935.               // save info about the line
  936.               //
  937.               stream.Write(&numPoints, sizeof numPoints);
  938.               stream.Write(&line.Color, sizeof line.Color);
  939.               stream.Write(&line.PenSize, sizeof line.PenSize);
  940.  
  941.               // save the points in the line
  942.               //
  943.               TPointsIterator pointsIter(line);
  944.               while (pointsIter) {
  945.                 TPoint point = pointsIter.Current();
  946.                 stream.Write(&point, sizeof point);
  947.                 pointsIter++;
  948.               }
  949.               linesIter++;
  950.             }
  951.  
  952.             stream.Commit(STGC_DEFAULT);
  953.           }
  954.           doc->GetStorage()->Commit(STGC_DEFAULT);
  955.  
  956.           // Update our caption with new file name
  957.           //
  958.           SetWindowText(hwnd, FileName);
  959.         }
  960.  
  961.         catch(TXOle& xole) {
  962.           MessageBox(hwnd, xole.why().c_str(), "EXCEPTION", MB_OK);
  963.         }
  964.       }
  965.     }
  966.   }
  967. }
  968.  
  969.  
  970. //
  971. // Handles CM_FILEOPEN command by loading saved parts and line data
  972. // (Variable 'FileName' contains the filename at this point)
  973. //
  974. void
  975. ViewWnd_OnFileOpen(HWND hwnd)
  976. {
  977.   ViewWndData* data = GetViewWndData(hwnd);
  978.   if (data) {
  979.     TOcDocument* doc = GetOleWinObj(hwnd)->GetOcDoc();
  980.     if (doc) {
  981.       try {
  982.         doc->SetStorage(FileName);
  983.         // load embedded objects
  984.         //
  985.         doc->LoadParts();
  986.  
  987.         TOcStorage* storage = doc->GetStorage();
  988.           if (storage) {
  989.             // open the stream that contains the lines
  990.             //
  991.             TOcStream stream(*storage, DEFDESC, false, STGM_READ);
  992.  
  993.             // how many lines?
  994.             //
  995.             int numLines;
  996.             stream.Read(&numLines, sizeof numLines);
  997.             for (int i=0; i<numLines; i++) {
  998.               // read the info about the line
  999.               //
  1000.               int numPoints;
  1001.               stream.Read(&numPoints, sizeof(numPoints));
  1002.               stream.Read(&CurrentColor, sizeof(CurrentColor));
  1003.               stream.Read(&CurrentPenSize, sizeof(CurrentPenSize));
  1004.               ScratchLine = new TLine(CurrentPenSize, CurrentColor);
  1005.  
  1006.               // read the points
  1007.               //
  1008.               for (int j=0; j<numPoints; j++) {
  1009.                 TPoint p;
  1010.                 stream.Read(&p, sizeof p);
  1011.                 ScratchLine->Add(p);
  1012.               }
  1013.               data->Lines->Add(*ScratchLine);
  1014.               delete ScratchLine;
  1015.               ScratchLine = 0;
  1016.             }
  1017.           InvalidateRect(hwnd, NULL, true);
  1018.         }
  1019.         SetWindowText(hwnd, FileName);
  1020.       }
  1021.       catch(TXOle& xole) {
  1022.          MessageBox(hwnd, xole.why().c_str(), "EXCEPTION", MB_OK);
  1023.       }
  1024.     }
  1025.   }
  1026. }
  1027.  
  1028.  
  1029. //
  1030. // Display Color Dialog to allow user to select pen color
  1031. //
  1032. void
  1033. ViewWnd_OnChoosePenColor(HWND hwnd)
  1034. {
  1035.   COLORREF userPal[16];
  1036.   memset(&userPal, 255, 16*sizeof(COLORREF));
  1037.   CHOOSECOLOR cc;
  1038.   memset(&cc, 0, sizeof cc);
  1039.   cc.lStructSize = sizeof cc;
  1040.   cc.hwndOwner = hwnd;
  1041.   cc.rgbResult = RGB(0, 0, 0);
  1042.   cc.lpCustColors = userPal;
  1043.   if (ChooseColor(&cc)) {
  1044.     CurrentColor = cc.rgbResult;
  1045.   }
  1046. }
  1047.  
  1048.  
  1049. //
  1050. // Handles WM_INITDIALOG for PenSize dialog
  1051. //
  1052. bool
  1053. PenDlg_OnInitDialog(HWND hwnd, HWND /*hwndFocus*/, LPARAM /*lParam*/)
  1054. {
  1055.   SetDlgItemInt(hwnd, IDC_PENSIZE, CurrentPenSize, false);
  1056.   return true;
  1057. }
  1058.  
  1059.  
  1060. //
  1061. // Handles WM_CLOSE message for PenSize dialog
  1062. //
  1063. void
  1064. PenDlg_OnClose(HWND hwnd)
  1065. {
  1066.   EndDialog(hwnd, IDCANCEL);
  1067. }
  1068.  
  1069.  
  1070. //
  1071. // Handles WM_COMMAND message from PenSize dialog
  1072. //
  1073. void
  1074. PenDlg_OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, uint /*codeNotify*/)
  1075. {
  1076.   switch (id) {
  1077.     case IDOK: {
  1078.       int penSize;
  1079.       int translated;
  1080.       penSize = GetDlgItemInt(hwnd, IDC_PENSIZE, &translated, FALSE);
  1081.  
  1082. #if !defined(NDEBUG)
  1083.       wsprintf(FileName, "ps = %d\n\r", penSize);
  1084.       OutputDebugString(FileName);
  1085. #endif
  1086.  
  1087.       if (penSize < 1 || 25 < penSize) {
  1088.         MessageBox(hwnd, "Pensize out of range.", "Error", MB_OK);
  1089.       } else {
  1090.         CurrentPenSize = penSize;
  1091.         EndDialog(hwnd, IDOK);
  1092.       }
  1093.       break;
  1094.     }
  1095.     case IDCANCEL: {
  1096.       EndDialog(hwnd, IDCANCEL);
  1097.       break;
  1098.     }
  1099.   }
  1100. }
  1101.  
  1102.  
  1103. //
  1104. // Callback of dialog which allows user to change pen size
  1105. //
  1106. bool CALLBACK _export
  1107. PenSizeDlgProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  1108. {
  1109.   switch (message) {
  1110.    case WM_INITDIALOG:
  1111.         HANDLE_WM_INITDIALOG(hwnd, wParam, lParam, PenDlg_OnInitDialog);
  1112.         return true;
  1113.  
  1114.    case WM_CLOSE:
  1115.         HANDLE_WM_CLOSE(hwnd, wParam, lParam, PenDlg_OnClose);
  1116.         return true;
  1117.  
  1118.    case WM_COMMAND:
  1119.         HANDLE_WM_COMMAND(hwnd, wParam, lParam, PenDlg_OnCommand);
  1120.         return true;
  1121.   }
  1122.   return false;
  1123. }
  1124.  
  1125.  
  1126. //
  1127. // Displays dialog which allows user to change pen size
  1128. //
  1129. void
  1130. ViewWnd_OnChoosePenSize(HWND hwnd)
  1131. {
  1132.   FARPROC proc = MakeProcInstance((FARPROC)PenSizeDlgProc, HInstance);
  1133.   DialogBox(HInstance, MAKEINTRESOURCE(ID_CHOOSEPENSIZE),
  1134.             hwnd, (DLGPROC)proc);
  1135.   FreeProcInstance(proc);
  1136. }
  1137.  
  1138.  
  1139. //
  1140. // Handles WM_COMMAND messages
  1141. //
  1142. void
  1143. ViewWnd_OnCommand(HWND hwnd, int id, HWND /*hwndCtl*/, uint /*codeNotify*/)
  1144. {
  1145.   switch(id) {
  1146.     case CM_FILEOPEN:
  1147.       ViewWnd_OnFileOpen(hwnd);
  1148.       break;
  1149.  
  1150.     case CM_FILESAVE:
  1151.     case CM_FILESAVEAS:
  1152.       ViewWnd_OnFileSaveAs(hwnd);
  1153.       break;
  1154.  
  1155.     case CM_PENCOLOR:
  1156.       ViewWnd_OnChoosePenColor(hwnd);
  1157.       break;
  1158.  
  1159.     case CM_PENSIZE:
  1160.       ViewWnd_OnChoosePenSize(hwnd);
  1161.       break;
  1162.  
  1163.     default:
  1164.       // Pass any command IDs that we're not handling to the OLE Helper
  1165.       // object. It will handle issues such as activating OLE UI dialogs.
  1166.       //
  1167.       GetOleWinObj(hwnd)->OnCommand(id);
  1168.       break;
  1169.   }
  1170. }
  1171.  
  1172.  
  1173. //
  1174. // Handles WM_LBUTTONDOWN message
  1175. //
  1176. void
  1177. ViewWnd_OnLButtonDown(HWND hwnd, bool fDoubleClick, int x, int y, uint keyFlags)
  1178. {
  1179.   // Pass LButtonDown/LButtonDblClk to the OLE Helper object.
  1180.   // It will deactiate/activate any OLE part if necessary
  1181.   //
  1182.   if (fDoubleClick)
  1183.     GetOleWinObj(hwnd)->OnLButtonDblClk(x, y, keyFlags);
  1184.   else {
  1185.     if (!GetOleWinObj(hwnd)->OnLButtonDown(x, y, keyFlags)) {
  1186.       if (!GetOleWinObj(hwnd)->SelectEmbedded()) {
  1187.         SetCapture(hwnd);
  1188.         MouseCaptured = true;
  1189.         ScratchLine = new TLine(CurrentPenSize, CurrentColor);
  1190.         TPoint p(x, y);
  1191.         ScratchLine->Add(p);
  1192.  
  1193.         CurPen = CreatePen(PS_INSIDEFRAME, CurrentPenSize, CurrentColor);
  1194.         DC = GetDC(hwnd);
  1195.         OldPen = SelectPen(DC, CurPen);
  1196.         MoveToEx(DC, x, y, 0);
  1197.       }
  1198.     }
  1199.   }
  1200. }
  1201.  
  1202.  
  1203. //
  1204. // Handles WM_MOUSEMOVE message
  1205. //
  1206. void
  1207. ViewWnd_OnMouseMove(HWND /*hwnd*/, int x, int y, uint /*keyFlags*/)
  1208. {
  1209.   if (MouseCaptured) {
  1210.     TPoint p(x, y);
  1211.  
  1212.     ScratchLine->Add(p);
  1213.     LineTo(DC, x, y);
  1214.   }
  1215. }
  1216.  
  1217.  
  1218. //
  1219. // Handles WM_LBUTTONUP message
  1220. //
  1221. void
  1222. ViewWnd_OnLButtonUp(HWND hwnd, int x, int y, uint /*keyFlags*/)
  1223. {
  1224.   if (MouseCaptured) {
  1225.     TPoint p(x, y);
  1226.     ScratchLine->Add(p);
  1227.  
  1228.     LineTo(DC, x, y);
  1229.     SelectPen(DC, OldPen);
  1230.     ReleaseDC(hwnd, DC);
  1231.  
  1232.     DeletePen(CurPen);
  1233.  
  1234.     ViewWndData* data = GetViewWndData(hwnd);
  1235.     data->Lines->Add(*ScratchLine);
  1236.  
  1237.     delete ScratchLine;
  1238.     ScratchLine = 0;
  1239.  
  1240.     ReleaseCapture();
  1241.     MouseCaptured = false;
  1242.   }
  1243. }
  1244.  
  1245.  
  1246. //
  1247. // Handles WM_INITMENU message
  1248. //
  1249. void
  1250. ViewWnd_OnInitMenu(HWND hwnd, HMENU hMenu)
  1251. {
  1252.   //
  1253.   // Allow OLE Helper object to enable/disable OLE related menuitems
  1254.   //
  1255.   GetOleWinObj(hwnd)->OnInitMenu(hMenu);
  1256. }
  1257.  
  1258.  
  1259. //
  1260. // Subdispatch OC_... messages
  1261. //
  1262. LRESULT
  1263. ViewWnd_OnOcEvent(HWND hwnd, WPARAM wParam, LPARAM lParam)
  1264. {
  1265.   // Pass the WM_OCEVENT from OCF to the OLE Helper Object
  1266.   //
  1267.   return GetOleWinObj(hwnd)->OnOcEvent(wParam, lParam);
  1268. }
  1269.  
  1270.  
  1271. //
  1272. // Standard message-handler routine for view window
  1273. //
  1274. LRESULT CALLBACK _export
  1275. ViewWndProc(HWND hwnd, uint message, WPARAM wParam, LPARAM lParam)
  1276. {
  1277.   switch (message) {
  1278.     HANDLE_MSG(hwnd, WM_CREATE,         ViewWnd_OnCreate);
  1279.     HANDLE_MSG(hwnd, WM_DESTROY,        ViewWnd_OnDestroy);
  1280.     HANDLE_MSG(hwnd, WM_PAINT,          ViewWnd_OnPaint);
  1281.     HANDLE_MSG(hwnd, WM_COMMAND,        ViewWnd_OnCommand);
  1282.     HANDLE_MSG(hwnd, WM_LBUTTONDOWN,    ViewWnd_OnLButtonDown);
  1283.     HANDLE_MSG(hwnd, WM_LBUTTONDBLCLK,  ViewWnd_OnLButtonDown);
  1284.     HANDLE_MSG(hwnd, WM_MOUSEMOVE,      ViewWnd_OnMouseMove);
  1285.     HANDLE_MSG(hwnd, WM_LBUTTONUP,      ViewWnd_OnLButtonUp);
  1286.     HANDLE_MSG(hwnd, WM_INITMENU,       ViewWnd_OnInitMenu);
  1287.     HANDLE_MSG(hwnd, WM_MDIACTIVATE,    ViewWnd_OnMDIActivate);
  1288.     HANDLE_MSG(hwnd, WM_SETFOCUS,       ViewWnd_OnSetFocus);
  1289.  
  1290.     case WM_OCEVENT:
  1291.       return ViewWnd_OnOcEvent(hwnd, wParam, lParam);
  1292.   }
  1293.  
  1294.   return ViewWnd_DefProc(hwnd, message, wParam, lParam);
  1295. }
  1296.  
  1297.